package com.moyun.common.exception;


import com.moyun.common.enums.CodeEnum;
import com.moyun.common.enums.ExceptionCodeEnum;
import com.moyun.model.common.R;
import com.moyun.common.utils.ResultUtil;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletResponse;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@RestControllerAdvice
@Slf4j
/**
 * 全局异常处理类
 */
public class GlobalExceptionHandler {

    private static final Logger LOG = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 查询结果为空时处理
     *
     * @param e
     * @return
     */
    @ExceptionHandler(EmptyResultException.class)
    public R emptyResultExceptionHandler(EmptyResultException e) {
        log.error("查询结果为空：{}", e.getMessage());
        return ResultUtil.fail(CodeEnum.FAIL);
    }

    /**
     * 请求参数错误时处理
     *
     * @param e
     * @return
     */
    @ExceptionHandler(RequestParamException.class)
    public R requestParamExceptionHandler(RequestParamException e) {
//        log.error("请求参数不合法：{}", e.getMessage());
        LOG.error("请求参数不合法：{}", e.getMessage());
        LinkedHashMap<String, Object> map = new LinkedHashMap<>();
        Set<String> set = new LinkedHashSet<>();
        return ResultUtil.fail(CodeEnum.FAIL);

    }

    /**
     * 系统拒绝访问异常(用户没有相应权限)
     *
     * @param e
     * @return
     */
    @ExceptionHandler(AccessDeniedException.class)
    public R accessDeniedException(AccessDeniedException e, HttpServletResponse response) {
        response.setContentType("application/json; charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        log.error("系统拒绝访问异常(用户没有相应权限)：{" + e.getMessage() + "}", e);
        return ResultUtil.fail(HttpServletResponse.SC_FORBIDDEN, "请联系管理员,获取此URL访问权限");
    }

    /**
     * 处理其他异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    public R exceptionHandler(Exception e, HttpServletResponse response) {
        response.setContentType("application/json; charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        log.error("服务器异常：{" + e.getMessage() + "}", e);
        /**
         * 生产环境上,不要让用户看到系统堆栈错误信息
         */
//        return ResultUtil.fail(CodeEnum.FAIL.getCode(), e.getMessage());
        return ResultUtil.fail(CodeEnum.FAIL.getCode(), "请联系开发人员解决");
    }

    /**
     * 处理 数据完整性违规 异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(DataIntegrityViolationException.class)
    public R DataIntegrityViolationExceptionHandler(DataIntegrityViolationException e, HttpServletResponse response) {
        response.setContentType("application/json; charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        // 数据库,不需要再打印一遍.  Druid 、MyBatis、MyBatisPlus 框架任意一个开启日志即可
        log.error("服务器异常：{" +e.getMessage()+"}",e);
        return ResultUtil.fail(CodeEnum.FAIL.getCode(), e.getCause().getMessage());
    }


    /**
     * 使用validation的参数校验注解，参数校验不通过抛的异常处理
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public R argumentNotValidErrorHandler(HttpServletResponse response, MethodArgumentNotValidException e) {
        response.setContentType("application/json; charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        BindingResult validateResult = e.getBindingResult();
        Map<String, String> collect = validateResult.getFieldErrors().stream().collect(Collectors.toMap(FieldError::getField, ObjectError::getDefaultMessage));
        return R.error(CodeEnum.FAIL.getCode(), "参数校验错误", collect);
    }

    /**
     * 接收参数格式转换异常
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public R argumentNotValidErrorHandler(HttpServletResponse response, HttpMessageNotReadableException e) {
        response.setStatus(HttpStatus.OK.value());
        return R.error(CodeEnum.FAIL.getCode(), "参数校验错误", e.getCause().getMessage());
    }

    /**
     * 空指针异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(NullPointerException.class)
    public R nullPointerException(NullPointerException e, HttpServletResponse response) {
        response.setContentType("application/json; charset=UTF-8");
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        log.error("空指针异常：{" + e.getMessage() + "}", e);
        return ResultUtil.fail(ExceptionCodeEnum.NULL_EXCEPTION.getCode(), "空指针异常");
    }


}
